/**
 * 对象
 */

var { log } = console;

// 创建对象
var obj = new Object();

// 向对象中添加属性
obj.name = '孙大圣'
obj.age = 500
log(obj); // { name: '孙大圣', age: 500 }
log(obj.name); // 孙大圣
log(obj.age); // 500

// 删除对象属性
delete obj.age
console.log(obj); // { name: '孙大圣' }



/**
 * 使用工厂方法创建对象
 */

function createPerson(name, age, gender) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.gender = gender;
    obj.sayName = function () {
        log(this.name);
    }
    return obj;
}

hong = createPerson('小红', 18, '女');
han = createPerson('小韩', 28, '男');


/**
 * 构造函数创建对象
 */

// 将sayName作为全局作用的方法
// 创建对象时，不会重复创建该方法，节省内存
function def() {
    log(this.name);
}

// 创建一个构造函数用来创建不同的对象
function Dog(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.sayName = def;
}
var dog = new Dog('阿黄', 10, '母');
log(dog.name); // 阿黄



/**
 * 原型对象
 */

// 每创建一个函数，解析器都会向函数中添加一个属性prototype
// prototype对应着一个对象，就是原型对象
// 原型对象就是一个公共区域，所有同一个类的实例都可以访问到该属性

// 1. demo
function MyPerson(name, age) {
    this.name = name;
    this.age = age;
}
// 在原型对象中添加属性或者方法
MyPerson.prototype.sex = '男';
var person = new MyPerson('Mike', 10);
log(person.name)  // 'Mike'
log(person.sex)  // '男'

// 2. 将构造函数改为原型对象方式访问
function ProtoDog(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
}
ProtoDog.prototype.sayName = function () {
    log(this.name);
}
var dog = new ProtoDog('小黑', 6, '公');
dog.sayName(); // 小黑



/**
 * 其他
 */

// 使用instanceof可以检查一个对象是否属于一个对象的实例
log(dog instanceof Dog); // false

// 使用hasOwnProperty()来检查对象是否含有该属性
log(dog.hasOwnProperty('ds')); // false

// 所有对象都是Objct的后代，称为基类
log(dog instanceof Object); // true


/**
 * 继承
 */

// 通过原型继承创建一个新的对象
function inherit(p) {
    if (p == null) throw TypeError(); // p是一个对象但不能为空
    if (Object.create) { // 如果Object.create存在，直接使用它，否则进行下一步检测
        return Object.create(p);
    }
    var t = typeof p;
    if (t !== 'object' && t !== 'function') throw TypeError();
    function f() { }; // 定义一个空构造函数
    f.prototype = p; // 将其原型属性设置为p
    return new f(); // 使用f()创建p的继承对象
}

// 对象的原型属性构成了一个链，通过这个链可以实现属性的继承
var o = {}
o.x = 1
var p = inherit(o) // p继承o和Object.prototype
p.y = 2
var q = inherit(o) // q继承o和Object.prototype
q.z = 3
log(q.x) // 1
log(q.y) // undefined
log(q.z) // 3
log(q.x + q.y) // NaN
log(p.x) // 1
log(p.y) // 2
log(p.z) // undefined
log(p.x + p.y) // 3
